package rbb.itm5.bwinf.roboter.View;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;

import javax.swing.JComponent;

import rbb.itm5.bwinf.roboter.Control.ControlerEvents;
import rbb.itm5.bwinf.roboter.Control.Roboter;
import rbb.itm5.bwinf.roboter.Model.Door;
import rbb.itm5.bwinf.roboter.Model.Obstacle;
import rbb.itm5.bwinf.roboter.Model.RoboterInterface;
import rbb.itm5.bwinf.roboter.Model.Step;

public class Room {

    private int OFFSET;
    private Graphics2D g;
    private View view;
    ControlerEvents event;
    private rbb.itm5.bwinf.roboter.Model.Room room;

    public Room(ControlerEvents event) {
        this.event = event;
        OFFSET = 20;
        view = new View();
        g = (Graphics2D) view.getGraphics();
    }

    public void paintBorder() {
        Door door = room.getDoor();
        g.setColor(Color.GREEN);

        //Linker und Rechter Rahmen
        g.fillRect(getOffset(), getOffset() + room.getGridSize(), room.getGridSize(), (room.getSize().height - 1) * room.getGridSize());
        g.fillRect(getOffset() + (room.getSize().width - 1) * room.getGridSize(), getOffset() + room.getGridSize(), room.getGridSize(), (room.getSize().height - 1) * room.getGridSize());

        //Oberer und Unterer Rahmen
        g.fillRect(getOffset() + room.getGridSize(), getOffset(), (room.getSize().width - 1) * room.getGridSize(), room.getGridSize());
        g.fillRect(getOffset() + room.getGridSize(), getOffset() + (room.getSize().height - 1) * room.getGridSize(), (room.getSize().width - 1) * room.getGridSize(), room.getGridSize());


        //Ecken Zeichen
        g.setColor(Color.YELLOW);
        g.fillRect(getOffset(), getOffset(), room.getGridSize(), room.getGridSize());
        g.fillRect(getOffset() + (room.getSize().width - 1) * room.getGridSize(), getOffset(), room.getGridSize(), room.getGridSize());
        g.fillRect(getOffset(), getOffset() + (room.getSize().height - 1) * room.getGridSize(), room.getGridSize(), room.getGridSize());
        g.fillRect(getOffset() + (room.getSize().width - 1) * room.getGridSize(), getOffset() + (room.getSize().height - 1) * room.getGridSize(), room.getGridSize(), room.getGridSize());


        g.setColor(Color.RED);
        g.drawLine(getOffset(), getOffset(), getOffset() + room.getGridSize(), getOffset() + room.getGridSize());
        g.drawLine(getOffset() + (room.getSize().width) * room.getGridSize(), getOffset(), getOffset() + (room.getSize().width - 1) * room.getGridSize(), getOffset() + room.getGridSize());
        g.drawLine(getOffset(), getOffset() + (room.getSize().height) * room.getGridSize(), getOffset() + room.getGridSize(), getOffset() + (room.getSize().height - 1) * room.getGridSize());
        g.drawLine(getOffset() + (room.getSize().width) * room.getGridSize(), getOffset() + (room.getSize().height) * room.getGridSize(), getOffset() + (room.getSize().width - 1) * room.getGridSize(), getOffset() + (room.getSize().height - 1) * room.getGridSize());

        g.setColor(Color.BLACK);
        g.drawRect(
                getOffset(),
                getOffset(),
                (room.getSize().width) * rbb.itm5.bwinf.roboter.Model.Room.GridSize,
                (room.getSize().height) * rbb.itm5.bwinf.roboter.Model.Room.GridSize);
        g.drawRect(
                getOffset() + rbb.itm5.bwinf.roboter.Model.Room.GridSize,
                getOffset() + rbb.itm5.bwinf.roboter.Model.Room.GridSize,
                (room.getSize().width - 2) * rbb.itm5.bwinf.roboter.Model.Room.GridSize,
                (room.getSize().height - 2) * rbb.itm5.bwinf.roboter.Model.Room.GridSize);



        //Tür Zeichen
        g.setColor(Color.BLACK);
        //g.fillRect(door.getPostion().x, door.getPostion().y, door.getSize(), door.getSize());
        switch (door.getOrientation()) {
            case Door.HORIZONTAL:
                g.clearRect(door.getPostion().x * room.getGridSize() + getOffset(), door.getPostion().y * room.getGridSize() + getOffset(), door.getSize() * room.getGridSize(), room.getGridSize() + 1);
                g.drawLine(door.getPostion().x * room.getGridSize() + getOffset(), door.getPostion().y * room.getGridSize() + getOffset(), door.getPostion().x * room.getGridSize() + getOffset(), door.getPostion().y * room.getGridSize() + getOffset() + room.getGridSize());
                g.drawLine(door.getPostion().x * room.getGridSize() + getOffset() + door.getSize() * room.getGridSize(), door.getPostion().y * room.getGridSize() + getOffset(), door.getPostion().x * room.getGridSize() + getOffset() + door.getSize() * room.getGridSize(), door.getPostion().y * room.getGridSize() + getOffset() + room.getGridSize());
                break;
            case Door.VERTICAL:
                g.clearRect(getOffset() + (door.getPostion().x) * room.getGridSize(), getOffset() + door.getPostion().y * room.getGridSize(), room.getGridSize() + 1, door.getSize() * room.getGridSize());
                g.drawLine(getOffset() + (door.getPostion().x) * room.getGridSize(), getOffset() + (door.getPostion().y) * room.getGridSize(), getOffset() + (door.getPostion().x + 1) * room.getGridSize(), getOffset() + (door.getPostion().y) * room.getGridSize());
                g.drawLine(getOffset() + (door.getPostion().x) * room.getGridSize(), getOffset() + (door.getPostion().y + door.getSize()) * room.getGridSize(), getOffset() + (door.getPostion().x + 1) * room.getGridSize(), getOffset() + (door.getPostion().y + door.getSize()) * room.getGridSize());
                break;
            default:
                break;
        }

    }

    public void paintObstacles() {
        paintObstacles(room.getObstacles(), Color.BLUE, 0, 0);
    }

    public void paintObstacles(ArrayList<Obstacle> obstacles, Color FillColor, int xOff, int yOff) {
        if (obstacles != null) {
            try {
                for (Obstacle obstacle : obstacles) {
                    Point position = obstacle.getPostion();
                    Dimension size = obstacle.getSize();
                    if (obstacle.isOnTheWall()) {
                        g.setColor(Color.PINK);
                    } else {
                        g.setColor(FillColor);
                    }
                    if(FillColor==Color.BLUE){
                        g.setPaint(new GradientPaint(0,0, new Color(50, 50, 200), 120, 150, new Color(120, 120, 255)));
                    }
                    g.fillRect((position.x + xOff) * room.getGridSize() + getOffset(), (position.y + yOff) * room.getGridSize() + getOffset(), size.width * room.getGridSize(), size.height * room.getGridSize());
                    g.setColor(Color.BLACK);
                    g.drawRect((position.x + xOff) * room.getGridSize() + getOffset(), (position.y + yOff) * room.getGridSize() + getOffset(), size.width * room.getGridSize(), size.height * room.getGridSize());
                    g.drawRect((position.x + xOff) * room.getGridSize() + 1 + getOffset(), (position.y + yOff) * room.getGridSize() + 1 + getOffset(), size.width * room.getGridSize() - 1, size.height * room.getGridSize() - 1);
                }
            } catch (ConcurrentModificationException e) {
                try {
                    Thread.sleep(30);
                    paintObstacles(obstacles, FillColor, xOff, yOff);
                } catch (InterruptedException e1) {
                }
            }
        }
    }

    public void paintRoboter(RoboterInterface roboter) {
        g.setColor(Color.RED);
        Point p = roboter.getPostion();
        p.x += room.getRoboterStartX();
        p.y += room.getRoboterStartY();
        g.fillOval(p.x * room.getGridSize() + getOffset(), p.y * room.getGridSize() + getOffset(), room.getGridSize(), room.getGridSize());
        g.setColor(Color.BLACK);
        g.drawOval(p.x * room.getGridSize() + getOffset(), p.y * room.getGridSize() + getOffset(), room.getGridSize(), room.getGridSize());
        g.setColor(Color.YELLOW);
        int directionSize=3;
        switch (roboter.getDirection()) {
            case RoboterInterface.DIRECTION_UP:
                g.fillOval(p.x * room.getGridSize() + ((room.getGridSize() / 2) - ((room.getGridSize() / directionSize) / 2)) + getOffset(), p.y * room.getGridSize() + getOffset(), room.getGridSize() / directionSize, room.getGridSize() / directionSize);
                break;
            case RoboterInterface.DIRECTION_RIGHT:
                g.fillOval(p.x * room.getGridSize() + room.getGridSize() - (room.getGridSize() / directionSize) + getOffset(), p.y * room.getGridSize() + ((room.getGridSize() / 2) - ((room.getGridSize() / directionSize) / 2)) + getOffset(), room.getGridSize() / directionSize, room.getGridSize() / directionSize);
                break;
            case RoboterInterface.DIRECTION_DOWN:
                g.fillOval(p.x * room.getGridSize() + ((room.getGridSize() / 2) - ((room.getGridSize() / directionSize) / 2)) + getOffset(), p.y * room.getGridSize() + room.getGridSize() - (room.getGridSize() / directionSize) + getOffset(), room.getGridSize() / directionSize, room.getGridSize() / directionSize);
                break;
            case RoboterInterface.DIRECTION_LEFT:
                g.fillOval(p.x * room.getGridSize() + getOffset(), p.y * room.getGridSize() + ((room.getGridSize() / 2) - ((room.getGridSize() / directionSize) / 2)) + getOffset(), room.getGridSize() / directionSize, room.getGridSize() / directionSize);
                break;
        }
    }

    public void paintRaster() {


        g.setColor(new Color(200, 150, 0));
        int raster = room.getGridSize() / 5;
        if (raster <= 0) {
            raster = 1;
        }
        for (int x = getOffset() + room.getGridSize(); x < getOffset() + (room.getSize().width) * room.getGridSize(); x += room.getGridSize()) {
            for (int y = getOffset() + room.getGridSize(); y < getOffset() + (room.getSize().height) * room.getGridSize(); y += room.getGridSize()) {
                if (y == getOffset()) {
                    continue;
                }
                g.drawLine(x, y - raster, x, y + raster);
            }
        }
        for (int y = getOffset() + room.getGridSize(); y < getOffset() + (room.getSize().height) * room.getGridSize(); y += room.getGridSize()) {
            for (int x = getOffset(); x < getOffset() + (room.getSize().width) * room.getGridSize(); x += room.getGridSize()) {
                if (x == getOffset()) {
                    continue;
                }
                g.drawLine(x - raster, y, x + raster, y);
            }
        }
        //StartPosition Zeichen
        g.setColor(Color.BLACK);
        g.fillOval(getOffset() + room.getRoboterStartX() * room.getGridSize(), getOffset() + room.getRoboterStartY() * room.getGridSize(), room.getGridSize(), room.getGridSize());
    }

    public void paintGoneSteps(Roboter roboter) {
        ArrayList<Step> steps = roboter.getSteps();
        g.setColor(Color.BLUE);
        for (Step step : steps) {
            if (step.isRotation()) {
                continue;
            }
            switch (step.getDirection()) {
                case Roboter.DIRECTION_UP:
                    g.drawLine(getOffset() + (step.getX() + room.getRoboterStartX() + 1) * room.getGridSize() - room.getGridSize() / 2,
                            getOffset() + (step.getY() + room.getRoboterStartY()) * room.getGridSize(),
                            getOffset() + (step.getX() + room.getRoboterStartX() + 1) * room.getGridSize() - room.getGridSize() / 2,
                            getOffset() + (step.getY() + room.getRoboterStartY() + 1) * room.getGridSize() - room.getGridSize() / 2);
                    break;
                case Roboter.DIRECTION_DOWN:
                    g.drawLine(getOffset() + (step.getX() + room.getRoboterStartX() + 1) * room.getGridSize() - room.getGridSize() / 2,
                            getOffset() + (step.getY() + room.getRoboterStartY()) * room.getGridSize() + room.getGridSize() / 2,
                            getOffset() + (step.getX() + room.getRoboterStartX() + 1) * room.getGridSize() - room.getGridSize() / 2,
                            getOffset() + (step.getY() + room.getRoboterStartY() + 1) * room.getGridSize());
                    break;
                case Roboter.DIRECTION_LEFT:
                    g.drawLine(getOffset() + (step.getX() + room.getRoboterStartX()) * room.getGridSize(),
                            getOffset() + (step.getY() + room.getRoboterStartY() + 1) * room.getGridSize() - room.getGridSize() / 2,
                            getOffset() + (step.getX() + room.getRoboterStartX() + 1) * room.getGridSize() - room.getGridSize() / 2,
                            getOffset() + (step.getY() + room.getRoboterStartY() + 1) * room.getGridSize() - room.getGridSize() / 2);
                    break;
                case Roboter.DIRECTION_RIGHT:
                    g.drawLine(getOffset() + (step.getX() + room.getRoboterStartX()) * room.getGridSize() + room.getGridSize() / 2,
                            getOffset() + (step.getY() + room.getRoboterStartY() + 1) * room.getGridSize() - room.getGridSize() / 2,
                            getOffset() + (step.getX() + room.getRoboterStartX() + 1) * room.getGridSize(),
                            getOffset() + (step.getY() + room.getRoboterStartY() + 1) * room.getGridSize() - room.getGridSize() / 2);
                    break;
            }
        }
    }

    public class View extends JComponent {

        public View() {
            this.setFocusable(true);
            this.requestFocus();
            this.addKeyListener(event);
            this.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    view.requestFocus();
                }
            });
        }
        /**
         *
         */
        private static final long serialVersionUID = -5142317894070350848L;
        boolean firstCall = true;

        @Override
        protected void paintComponent(Graphics g) {
            g.clearRect(0, 0, this.getWidth(), this.getHeight());
            Room.this.g = (Graphics2D) g;
            Room.this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            Room.this.g.setPaint(Color.GRAY);
            if (firstCall) {
                this.requestFocus();
                event.ViewWasFirstCalled();
            } else {
                g.setColor(Color.WHITE);
                g.fillRect(getOffset(), getOffset(), room.getSize().width * room.getGridSize(), room.getSize().height * room.getGridSize());
            }
            event.repaintRoomFromView();
            firstCall = false;
        }
    }

    View getView() {
        return view;
    }

    public void repaint() {
        view.repaint();
    }

    public Dimension getSize() {
        return view.getSize();
    }

    public int getOffset() {
        return OFFSET;
    }

    public void setViewSize(int width, int height) {
        view.setPreferredSize(new Dimension(width + getOffset() * 2, height + getOffset() * 2));
        view.revalidate();
        view.validate();
    }

    public void setRoomModel(rbb.itm5.bwinf.roboter.Model.Room room) {
        this.room = room;
    }
}
